package han.chensing.latos.common.level.content.timeLine.frame;

import java.io.Serial;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;

import han.chensing.latos.common.level.function.TimeObject;

public class FrameGeneral extends BaseFrame<GeneralEventTypes> implements Serializable, TimeObject {
    @Serial
    private static final long serialVersionUID = -8321924341412380809L;

    private float x;
    private float y;
    private float rotate;
    private float alpha;
    private float speed;
    private float bpm;

    public FrameGeneral() {
        this.eventTypes=new GeneralEventTypes[GeneralEventTypes.values().length];
    }

    public FrameGeneral(FrameGeneral frame) {
        if (frame==null)
            return;
        this.x=frame.x;
        this.y=frame.y;
        this.rotate=frame.rotate;
        this.alpha=frame.alpha;
        this.speed=frame.speed;
        this.bpm=frame.bpm;
        this.time=frame.time;
        this.eventTypes=new GeneralEventTypes[GeneralEventTypes.values().length];
        addTypes(frame.eventTypes);
    }

    public float getValueFromSingleEventType(){
        if (eventTypes.length==0)return 0;
        return switch (eventTypes[0]){
            case X -> x;
            case Y -> y;
            case Alpha -> alpha;
            case Rotate -> rotate;
            case Speed -> speed;
        };
    }

    public GeneralEventTypes[] getEventTypes() {
        return eventTypes;
    }

    public void setEventTypes(GeneralEventTypes[] generalEventTypes) {
        this.eventTypes = generalEventTypes;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public float getRotate() {
        return rotate;
    }

    public void setRotate(float rotate) {
        this.rotate = rotate;
    }

    public float getAlpha() {
        return alpha;
    }

    public void setAlpha(float alpha) {
        this.alpha = alpha;
    }

    public float getSpeed() {
        return speed;
    }

    public void setSpeed(float speed) {
        this.speed = speed;
    }

    public float getBpm() {
        return bpm;
    }

    public void setBpm(float bpm) {
        this.bpm = bpm;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        FrameGeneral frame = (FrameGeneral) o;
        return
                Float.compare(frame.time, time) == 0 &&
                eventTypePosition == frame.eventTypePosition &&
                Float.compare(frame.x, x) == 0 &&
                Float.compare(frame.y, y) == 0 &&
                Float.compare(frame.rotate, rotate) == 0 &&
                Float.compare(frame.alpha, alpha) == 0 &&
                Float.compare(frame.speed, speed) == 0 &&
                Arrays.equals(eventTypes, frame.eventTypes);
    }

    @Override
    public int hashCode() {
        int result = Objects.hash(time, eventTypePosition, x, y, rotate, alpha, speed);
        result = 31 * result + Arrays.hashCode(eventTypes);
        return result;
    }

    public static FrameGeneral mergeFrame(FrameGeneral frame1, FrameGeneral frame2){
        FrameGeneral frame=new FrameGeneral();
        frame.setX(frame1.getX()+frame2.getX());
        frame.setY(frame1.getY()+frame2.getY());
        frame.addTypes(frame1.getEventTypes());
        frame.addTypes(frame2.getEventTypes());
        frame.setRotate(frame1.getRotate()+frame2.getRotate());
        frame.setAlpha(frame1.getAlpha()+frame2.getAlpha());
        frame.setSpeed(frame1.getSpeed()+frame2.getSpeed());
        return frame;
    }

    public static FrameGeneral overlappingFrames(FrameGeneral... frames){
        if (frames==null)
            return null;
        FrameGeneral frame=new FrameGeneral();
        for (FrameGeneral frame1 : frames) {
            if (frame1==null)continue;
            frame= mergeFrame(frame1,frame);
        }
        return frame;
    }
}
